package cn.tedu.mall.seckill.timer;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.pojo.seckill.model.SeckillSku;
import cn.tedu.mall.pojo.seckill.model.SeckillSpu;
import cn.tedu.mall.seckill.mapper.SeckillSkuMapper;
import cn.tedu.mall.seckill.mapper.SeckillSpuMapper;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
public class SeckillInitialJob implements Job {
    @Autowired
    private RedisTemplate redisTemplate; //缓存随机码
    //库存需要直接在Redis中进行数据的操作，所以需要以字符串的形式保存
    //直接在Redis中操作库存数：方便、安全(防止超卖)
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //查询spu得到sku列表，获取到库存数
    @Autowired
    private SeckillSpuMapper seckillSpuMapper;
    @Autowired
    private SeckillSkuMapper seckillSkuMapper;


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //缓存预热，设计一个在秒杀业务开始前进行缓存预热的时间(比如：开始前5分钟开始预热)
        //意思就是在当前时间+5分钟后开始进行秒杀活动
        LocalDateTime time = LocalDateTime.now().plusMinutes(5);
        //利用time进行查询
        List<SeckillSpu> seckillSpus = seckillSpuMapper.selectSeckillSpusByTime(time);
        //判断seckillSpus是否为null，如果不为null，我们继续
        if (seckillSpus==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"当前时间不在秒杀时间范围内");
        //开始预热
        for (SeckillSpu seckillSpu : seckillSpus) {
            //获取spuId，根据spuId获取到sku的列表
            Long spuId = seckillSpu.getSpuId();
            List<SeckillSku> seckillSkus = seckillSkuMapper.selectSeckillSkusBySpuId(spuId);
            //遍历seckillSkus，获取到库存，进行预热
            for (SeckillSku seckillSku : seckillSkus) {
                //获取skuId和库存
                Long skuId = seckillSku.getSkuId();
                Integer seckillStock = seckillSku.getSeckillStock();
                log.info("开始为{}号商品开始预热",skuId);
                //获取Redis中对应的key
                String stockKey = SeckillCacheUtils.getStockKey(skuId);
                //检查redis中是否有stockKey
                if(redisTemplate.hasKey(stockKey)){
                    log.info("已经为{}号商品添加库存预热了",skuId);
                }else{
                    //开始向Redis中进行缓存
                    stringRedisTemplate.boundValueOps(stockKey).set(seckillStock+""
                            ,24*60*60 + RandomUtils.nextInt(100), TimeUnit.SECONDS);
                    log.info("成功为{}号商品添加库存",skuId);
                }
            }
            //生成随机码进行缓存
            //获取随机码的key值
            String randCodeKey = SeckillCacheUtils.getRandCodeKey(spuId);
            //判断key是否存在
            if(redisTemplate.hasKey(randCodeKey)){
                //存在，取出数据，方便测试
                int randCode = (int) redisTemplate.boundValueOps(randCodeKey).get();
                log.info("{}号商品的随机码为{}",spuId,randCode);
            }else{
                //生成随机码
                int randCode = RandomUtils.nextInt(900000) + 100000;
                redisTemplate.boundValueOps(randCodeKey).set(randCode,
                        24*60*60 + RandomUtils.nextInt(100), TimeUnit.SECONDS);
                log.info("成功为{}号商品添加了随机码{}",spuId,randCode);
            }
        }
    }
}
